<!DOCTYPE html>
<html>
<head>
    <!-- 生命游戏 -->
    <!-- 
        https://news.html5.qq.com/share/1186393055?ch=060000&tabId=0&tagId=MttTagSource&docId=1186393055&url=http%3A%2F%2Fgames.qq.com%2Fa%2F20170111%2F018702.htm&clientWidth=360&dataSrc=&qburl=qb%3A%2F%2Fext%2Fread%3Fcid%3DMttTagSource%26type%3D0%26mttsummaryid%3D1186393055%26b_f%3D060000%26bizid%3D1&sc_id=OmSopmB
     -->
    <title>生命游戏</title>
    <meta charset="utf-8">
    <style type="text/css">
        .disc {
        }
        .disc table {
            border-collapse: collapse;
            border-spacing: 0;
            width: auto;
            margin: 0 auto;
            /*border: 3px solid #888;*/
        }
        .disc table tr {
            display: block;
            overflow: hidden;
        }
        .disc table td {
            display: block;
            float: left;
            width: 100px;
            height: 100px;
            border: 1px solid #444;
        }
        .selected {
            background-color: red;
        }
    </style>
</head>
<body>
    <div class="disc">
        <table id="DiscTable">
        </table>
    </div>
</body>
</html>
<script type="text/javascript">
    window.onload = function(){
        LifeGame({
            row_count: 20,
            colu_count: 20,
            id: "DiscTable",
            init_count: 110,
            IntervalTimes: 2000,
            init_postions: [
            ]
        });
    }

</script>
<script type="text/javascript">
    var LifeGame = (function() {
        function Init(Config) {
            Config = Config || {};

            var disc = {
                element: getElementById(Config.id),
                // 默认设置
                config: {
                    id: Config.id,
                    row_count: Config.row_count || 10,
                    colu_count: Config.colu_count || 10,
                    init_count: Config.init_count || Math.round((10*10) * 0.3),
                    IntervalTimes: Config.IntervalTimes || 60,
                    init_postions: Config.init_postions || []
                }
            };

            // 创建游戏地图
            CreateDisc(disc);
            log("地图总空格: " + getElementByTag("td").length);

            // 初始化第一批细胞
            InitPattern(disc)

            setInterval(function(){
                nextPlay(disc);
            }, disc.config.IntervalTimes);
        }
        
        function getElementByTag(name){
            return document.getElementsByTagName(name);
        }
        function getElementById(id){
            return document.getElementById(id);
        }
        function log(object) {
            console.log(object)
        }

        function CreateDisc(disc) {
            for (var i = 1; i <= disc.config.row_count; i++) {
                var rowObj = document.createElement("tr");
                rowObj.id = getid(i,0);

                for (var y = 1; y <= disc.config.colu_count; y++) {
                    var coluObj = document.createElement("td");
                    coluObj.id = getid(i,y)

                    rowObj.appendChild(coluObj);
                }
                disc.element.appendChild(rowObj);
            }
        }

        function getid(rowid, coluid) {
            return "disc_" + rowid + "_" + coluid;
        }

        function InitPattern(disc) {
            if (disc.config.init_postions.length <= 0) {
                randomInit(disc);
            } else {
                for (var i = 0; i < disc.config.init_postions.length; i++) {
                    var arr=disc.config.init_postions[i];
                    var idstr = getid(arr[0], arr[1]);
                    addClass(idstr);
                }
            }
        }

        function randomInit(disc) {
            for (var i = 0; i < disc.config.init_count; i++) {
                var rowid = getRound(1, disc.config.row_count);
                var coluid = getRound(1, disc.config.colu_count);

                var idstr = getid(rowid, coluid);
                addClass(idstr);
            }
        }

        function getRound(n, m) {
            return Math.round(Math.random()*(m-n) + n);
        }

        function nextPlay(disc) {
            var arr_si = new Array();
            var arr_sheng = new Array();
            var arr_fanyan = new Array();

            for (var x = 1; x <= disc.config.row_count; x++) {
                for (var y = 1; y <= disc.config.colu_count; y++) {
                    switch(getState(disc,x,y))
                    {
                        case 0:
                        case 1: // 死: 与1个或0个细胞相邻,则因为孤独而死
                        case 4:
                        case 5:
                        case 6:
                        case 7:
                        case 8: // 死: 与4个及以上细胞相邻,则因为过度拥挤而死
                            arr_si.push(getid(x,y));
                            break;
                        case 2:
                        case 3: // 生: 与2或3个细胞相邻的细胞将活到下一轮
                            arr_sheng.push(getid(x,y));
                            break;
                        case -3: // 繁衍: 一个空格若与3个细胞相邻,则在下一轮时,这个空格内将产生一个新细胞
                            arr_fanyan.push(getid(x,y));
                            break;
                        default:
                            break;
                    }
                }
            }

            for (var i = 0; i < arr_si.length; i++) {
                removeClass(arr_si[i]);
            }
            for (var i = 0; i < arr_fanyan.length; i++) {
                addClass(arr_fanyan[i]);
            }
        }

        function getState(disc, x, y) {
            var isifCount = 0;

            isifCount += isHasClass(getid(x-1, y-1));
            isifCount += isHasClass(getid(x-1, y));
            isifCount += isHasClass(getid(x-1, y+1));

            isifCount += isHasClass(getid(x, y-1));
            isifCount += isHasClass(getid(x, y+1));

            isifCount += isHasClass(getid(x+1, y-1));
            isifCount += isHasClass(getid(x+1, y));
            isifCount += isHasClass(getid(x+1, y+1));

            if (isHasClass(getid(x, y)) == 0) {
                isifCount *= -1;
            }
            return isifCount;
        }
        function isHasClass(idstr) {
            if (contains(idstr)) {
                return 1;
            }
            return 0;
        }
        
        function addClass(idstr) {
            var tdelement=getElementById(idstr);
            tdelement.classList.add("selected");
            tdelement.innerHTML=idstr;
        }
        function removeClass(idstr) {
            var tdelement=getElementById(idstr);
            tdelement.classList.remove("selected");
            tdelement.innerHTML="";
        }
        function contains(idstr) {
            var tdelement=getElementById(idstr);
            if (tdelement==null) {
                return false;
            }
            return tdelement.classList.contains("selected");
        }
        
        return Init;
    })();
</script>
